package it.uniba.di.mas.jpnde.behaviour;

import java.io.IOException;

import it.uniba.di.mas.jpnde.core.PNContext;
import it.uniba.di.mas.jpnde.core.PlaceEvent;
import it.uniba.di.mas.jpnde.core.PN;
import it.uniba.di.mas.jpnde.core.IPNActionListener;
import it.uniba.di.mas.jpnde.core.Place;
import it.uniba.di.mas.jpnde.core.Token;
import it.uniba.di.mas.jpnde.core.Transition;
import jade.core.AID;
import jade.core.behaviours.Behaviour;
import jade.lang.acl.ACLMessage;
import jade.util.leap.List;

public class PNManagerRun extends Behaviour
	implements IPNActionListener{
	
	private PN pn=null;
	private Thread t=null;
	private String messageError="";
	
	public PNManagerRun(PN pn){
		this.pn=pn;
	}
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private final static short INIT_RUN=0;
	private final static short RUN=1;
	private final static short END=2;
	private final static short ERROR=3;
	
	private short state=INIT_RUN;
	
	@Override
	public void action() {
		// TODO Auto-generated method stub
		switch(state){
		case INIT_RUN:
			initRun();
			break;
		case RUN:
			running();
			break;
		}	
	}

	private void initRun(){
		System.out.println("PNManagerRun.initRun ");
		try {
			pn.initialize();
			pn.addActionListener(this);
			t=new Thread(pn);
			t.start();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			state=ERROR;
			return;
		}
		state=RUN;
	}
	
	private void running(){
		//System.out.println("PNManagerRun.running ");
		ACLMessage message=myAgent.receive();
		if (message!=null)
			{
			try {
			
			switch(message.getPerformative())
			{
			case ACLMessage.INFORM:
				// Input Event - Token
				if ((message.hasByteSequenceContent())&&
					(message.getContentObject() instanceof Token))
					pn.receiveToken((Token)message.getContentObject());
				// Transition - end
				if ((message.hasByteSequenceContent())&&
					(message.getContentObject() instanceof Transition))
					pn.endTransition((Transition)message.getContentObject());
				break;
			case ACLMessage.FAILURE:
					messageError=message.getContent();
					state=ERROR;
				break;
			case ACLMessage.CANCEL:
					if (pn.getConsoleId().equals(message.getSender().getName()))
						state=END;
				break;	
			default: 	  
			       System.out.println("PNManagerRun.running :"+pn.getId()+
				      " performative <"+message.getPerformative()+"> not recognized !");
			}
			
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				state=ERROR;
				return;
				}
			}
		else
			block();
	}
	
	@Override
	public boolean done() {
		// TODO Auto-generated method stub
		return state==ERROR||state==END;
	}
	
	public int onEnd() {
		System.out.println("PNManagerRun.onEnd :"+pn.getId());
		pn.stop();
		if (t.isAlive())
			t.interrupt();
		int ret=super.onEnd();
		if (state==ERROR)
			System.out.println("PNManagerRun.onEnd: ErrorMessage<"+this.messageError+">");
		
		// Stop event and transition
		ACLMessage message=new ACLMessage(ACLMessage.CANCEL);
		for(int i=0;i<pn.getPlaces().size();i++)
			{
				Place p=(Place)pn.getPlaces().get(i);
				if (p.getEvent()!=null)
					message.addReceiver(new AID(p.getEvent().getAgentId(),AID.ISGUID));
			}
		for(int i=0;i<pn.getTransitions().size();i++)
			{
			Transition t=(Transition)pn.getTransitions().get(i);
			message.addReceiver(new AID(t.getAgentId(),AID.ISGUID));
			}
		myAgent.send(message);
		
		ACLMessage consoleMessage=null;
		if (state==ERROR){
			consoleMessage=new ACLMessage(ACLMessage.FAILURE);
			consoleMessage.addReceiver(new AID(pn.getConsoleId(),AID.ISGUID));
			consoleMessage.setContent(messageError);
		} else {
			consoleMessage=new ACLMessage(ACLMessage.INFORM);
			consoleMessage.addReceiver(new AID(pn.getConsoleId(),AID.ISGUID));
			consoleMessage.setContent(pn.getId());
		}
		myAgent.send(consoleMessage);
		
		myAgent.doDelete();
		return ret;
	}

	@Override
	public void errorAction(String errorMessage) {
		// TODO Auto-generated method stub
		System.out.println("PNManagerRun.errorAction :"+pn.getId());
		messageError=errorMessage;
		state=ERROR;
		restart();
	}

	@Override
	public void transictionAction(Transition trans,List tokens){
		// TODO Auto-generated method stub
		System.out.println("PNManagerRun.transictionAction :"+trans.getId());
		ACLMessage message=new ACLMessage(ACLMessage.REQUEST);
		message.addReceiver(new AID(trans.getAgentId(),AID.ISGUID));
		try {
			PNContext context=pn.getContext();
			context.setTokens(tokens);
			message.setContentObject(pn.getContext());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			messageError="PNManagerRun.transictionAction :"+e.getMessage();
			state=ERROR;
			return;
		}
		myAgent.send(message);
	}

	@Override
	public void endAction() {
		// TODO Auto-generated method stub
		System.out.println("PNManagerRun.endAction :"+pn.getId());
		state=END;
		restart();
	}

	@Override
	public void outEventAction(Place place,Token token) {
		// TODO Auto-generated method stub
		System.out.println("PNManagerRun.outEventAction :"+place.getId());
		PlaceEvent event=place.getEvent();
		ACLMessage message=new ACLMessage(ACLMessage.INFORM);
		message.addReceiver(new AID(event.getAgentId(),AID.ISGUID));
		try {
			message.setContentObject(token);
			} 
		catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			messageError="PNManagerRun.outEventAction :"+e.getMessage();
			state=ERROR;
			return;
			}
		myAgent.send(message);
	}
}
